package com.zed.api.domain;

import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * {@link Member}, DDD聚合根/实体的成员,可延迟加载的部分。<br>
 * 一个聚合根或者实体的{@link Member}字段为null,表明从未对此字段进行延迟加载。<br>
 * 如果{@link Member}不为null，仅仅{@link Member#get()}==null,表示已经执行延迟加载，但加载后的结果为null.
 *
 * @author Zed
 */
public final class Member<T> implements Serializable, AggregatableAware {

    /**
     *
     */
    private static final long serialVersionUID = 626710134455293987L;
    private T value;

    /**
     * 构造方法，用于反序列化
     */
    protected Member() {
    }

    /**
     * 构造方法
     *
     * @param value {@link T},成员的值
     */
    public Member(T value) {
        this.value = value;
    }

    /**
     * 获取成员值
     *
     * @return {@link T}
     */
    public T get() {
        return this.value;
    }

    /**
     * 判断内部值是否存在
     *
     * @return {@link boolean},返回{@code true}表示存在，不为null,否则返回{@code false}
     */
    public boolean isPresent() {
        return this.value != null;
    }

    /**
     * 当内部值不为null时，执行{@code consumer}的消费逻辑
     *
     * @param consumer {@link Consumer},消费者
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * 获取成员值，如果为null,则返回缺省值
     *
     * @param defaultValue {@link T},缺省值
     * @return {@link T
     */
    public T getOrElse(T defaultValue) {
        return this.value == null ?
                defaultValue :
                this.value;
    }

    /**
     * 获取成员值，如果成员值为null,则返回{@code  other}提供的数据
     *
     * @param other {@link Supplier},数据提供者
     * @return {@link T}
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 获取成员值，如果成员值为null,则抛出{@code exceptionSupplier}提供的例外
     *
     * @param <X>
     * @param exceptionSupplier {@link Supplier},例外提供者
     * @return {@link T}
     * @Throws X
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }


    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Optional)) {
            return false;
        }

        Member<?> other = (Member<?>) obj;
        return Objects.equals(value, other.value);
    }

    /* (non-Javadoc)
     * @see org.camellia.model.domain.AggregatableAware#setAggregate(org.camellia.model.domain.Aggregatable)
     */
    @Override
    public void setAggregate(Aggregatable<?> aggregate) {
        AggregatableAware.mayBeToBind(this.value, aggregate);
    }

    /**
     * 创建一个空的实例
     *
     * @param <T>
     * @return {@link Member}
     */
    public static <T> Member<T> empty() {
        return new Member<T>();
    }

    /**
     * 根据{@code value},创建新实例
     *
     * @param <T>
     * @param value {@link T}
     * @return {@link Member}
     */
    public static <T> Member<T> of(T value) {
        return new Member<>(value);
    }
}
